#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#define LOG_FILE "test.log"

// 修改 log_message 函数，支持在终端和文件中同时输出
void log_message(const char *format, ...) {
    FILE *log_file = fopen(LOG_FILE, "a");
    if (log_file == NULL) {
        perror("无法打开日志文件");
        exit(1);
    }

    va_list args;
    va_start(args, format);
    
    // 打印到终端
    vprintf(format, args);

    // 同时打印到文件
    vfprintf(log_file, format, args);
    
    va_end(args);

    fclose(log_file);
}

int main() {
    int *ptr1, *ptr2;
    size_t size1 = 10 * sizeof(int);  // 分配 40 byte的内存
    size_t size2 = 100 * sizeof(int); // 分配 100*4字节大小的内存

    // 测试 1: 分配内存并写入数据
    log_message(" 分配内存并写入数据。\n");
    ptr1 = (int *)malloc(size1);
    if (ptr1 == NULL) {
        log_message("内存分配失败: ptr1\n");
        return 1;
    }
    log_message("内存分配成功: ptr1\n");
    log_message("分配的内存大小: 40 byte\n");
    log_message("内存ptr1 地址: %p\n", ptr1); // 打印内存地址

    for (int i = 0; i < 10; i++) {
        ptr1[i] = i * i; // 存储平方数
    }

    // 测试 2: 再次分配更多内存并写入数据
    log_message("分配400 byte内存并写入数据。\n");
    ptr2 = (int *)malloc(size2);
    if (ptr2 == NULL) {
        log_message("内存分配失败: ptr2\n");
        free(ptr1);  // 释放已分配的内存
        return 1;
    }
    log_message("内存分配成功: ptr2\n");
    log_message("分配的内存大小: 400 byte\n");
    log_message("ptr2 地址: %p\n", ptr2); // 打印内存地址

    for (int i = 0; i < 100; i++) {
        ptr2[i] = i * i; // 存储平方数
    }

    // 测试 3: 内存释放
    log_message("释放内存并检查。\n");
    free(ptr1);
    log_message("ptr1 指向的内存 释放成功。\n");
    ptr1 = NULL; // 释放后将指针置为 NULL

    free(ptr2);
    log_message("ptr2 指向的内存 释放成功。\n");
    ptr2 = NULL; // 释放后将指针置为 NULL

    // 测试 4: 内存异常处理（访问已释放的内存）
    log_message("访问已释放的内存（异常）。\n");
    if (ptr1 != NULL) {
        log_message("错误: 仍然尝试访问已释放的内存 ptr1\n");
    } else {
        log_message("成功捕获对已释放内存的访问错误。\n");
    }

    // 测试 5: 异常访问
    log_message("访问保留区内存地址0x00");

    int *p = (int *)0x00;
    log_message("%d\n", *p);

    // 测试 6: 内存访问异常后正确退出
    log_message(" 程序正常退出。\n");
    free(ptr1);
    return 0;
}

